package com.sntk.organauthomanager.application.service;

import com.sntk.organauthomanager.application.dto.HisOperatorInfo;
import com.sntk.organauthomanager.application.dto.ServiceInfo;
import com.sntk.organauthomanager.domain.model.AffiliateInfo;
import com.sntk.organauthomanager.domain.model.Organization;
import com.sntk.organauthomanager.domain.model.User;
import com.sntk.organauthomanager.domain.model.UserAffiliate;
import com.sntk.organauthomanager.domain.repository.OrganizationRepository;
import com.sntk.organauthomanager.domain.repository.UserAffiliateRepository;
import com.sntk.organauthomanager.domain.repository.UserRepository;
import com.sntk.organauthomanager.infrastructure.exception.ObjectNotFoundException;
import com.sntk.organauthomanager.infrastructure.exception.ServiceLostConnectionException;
import com.sntk.organauthomanager.infrastructure.service.ServiceConfig;
import com.sntk.organauthomanager.infrastructure.service.ServiceConfigInfo;
import com.sntk.organauthomanager.infrastructure.utils.IPUtil;
import com.sntk.organauthomanager.infrastructure.utils.JwtUtil;
import com.sntk.organauthomanager.infrastructure.utils.NumberConvertUtils;
import com.sntk.organauthomanager.infrastructure.utils.RestTemplateUtil;
import io.jsonwebtoken.Claims;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.servlet.http.HttpServletRequest;
import java.util.List;
import java.util.UUID;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

/**
 * @ClassName: InteriorRegistrationService
 * @author: wgchao
 * @createTime: 2020/9/7 4:37 PM
 * @Description: 内部注册服务
 */
@Service
@Transactional(rollbackFor = Exception.class)
public class InteriorRegistrationService {
    @Autowired
    private UserRepository userRepository;
    @Autowired
    private UserAffiliateRepository userAffiliateRepository;
    @Autowired
    private OrganizationRepository organizationRepository;
    @Autowired
    private JwtUtil jwtUtil;

    private ExecutorService executorService = Executors.newFixedThreadPool(20);

    private static final Logger logger = LoggerFactory.getLogger(InteriorRegistrationService.class);

    /**
     * 服务注册
     * @param serviceInfo 服务信息
     * @return 返回服务编号
     */
    public String serviceRegistration(ServiceInfo serviceInfo, HttpServletRequest request){
        //获取客户真实IP
        String encodeip = IPUtil.getIpAddr(request);
        //生成服务编号(ip+UUID)
        String serviceCode = encodeip+"&"+NumberConvertUtils.hex16To10(UUID.randomUUID().toString().split("-")[0]).toString();

        //调用服务检测地址 检查服务可用性
        try{
            String backStr = RestTemplateUtil.getForm(serviceInfo.getDetectUrl(), String.class);
        }catch (Exception e){
            e.printStackTrace();
            throw new ServiceLostConnectionException(serviceInfo.getDetectUrl());
        }

        //注册服务
        ServiceConfig.addService(new ServiceConfigInfo(serviceCode, serviceInfo.getServiceName(), encodeip, serviceInfo.getDetectUrl()));

        return serviceCode;
    }


    /**
     * 用户认证
     * @param token
     * @return 返回用户信息
     */
    public HisOperatorInfo autho(String token){
        Claims claims = jwtUtil.parseJWT(token);
        if(claims == null){//token解析错误
            throw new RuntimeException("验证信息无效！");
        }
        String uname = claims.getId();
        User user = userRepository.findByKey(uname);
        if(user == null){
            throw new ObjectNotFoundException("账户不存在");
        }
        user.normalException();

        if(claims.getSubject().equals(user.getInstitutionNumber())){
            Organization organization = organizationRepository.findByKey(user.getInstitutionNumber());
            if(organization == null){
                throw new ObjectNotFoundException("用户所在机构不存在");
            }
            return new HisOperatorInfo(user.getUname(), user.getUserName(),
                    claims.getSubject(), user.getUserType().getIndex(),
                    organization.getHisInstitutionNumber(), organization.getInstitutionName(), user.getHisCode());
        }else{
            //查询用户机构关联关系
            UserAffiliate userAffiliate = userAffiliateRepository.findByKey(uname);
            if(userAffiliate == null){
                throw new ObjectNotFoundException("用户不存在该机构关联");
            }
            AffiliateInfo affiliateInfo = userAffiliate.findByOrgan(claims.getSubject());
            if(affiliateInfo == null){
                throw new ObjectNotFoundException("用户不存在该机构关联");
            }
            Organization organization = organizationRepository.findByKey(affiliateInfo.getInstitutionNumber());
            if(organization == null){
                throw new ObjectNotFoundException("用户关联机构不存在");
            }
            return new HisOperatorInfo(user.getUname(), user.getUserName(),
                    claims.getSubject(), user.getUserType().getIndex(),
                    affiliateInfo.getHisCode(), organization.getInstitutionName(), user.getHisCode());
        }
    }


    /**
     * 内部服务心跳检测（五分钟检测一次）
     */
    public void heartbeatDetection(){
        List<ServiceConfigInfo> serviceConfigInfos = ServiceConfig.findAllService();
        if(serviceConfigInfos!=null && !serviceConfigInfos.isEmpty()){
            for(ServiceConfigInfo serviceConfigInfo : serviceConfigInfos){
                logger.info(serviceConfigInfo.getServiceName()+"服务心跳检测");
                // 另起线程
                executorService.execute(new Runnable() {
                    @Override
                    public void run() {
                        //调用服务检测地址 检查服务可用性
                        try{
                            String backStr = RestTemplateUtil.getForm(serviceConfigInfo.getDetectUrl(), String.class);
                            //检测成功 重置失联次数
                            logger.info(serviceConfigInfo.getServiceName()+"服务心跳检测-正常");
                            serviceConfigInfo.reset();
                            ServiceConfig.updateService(serviceConfigInfo);
                        }catch (Exception e){
                            logger.info(serviceConfigInfo.getServiceName()+"服务心跳检测-异常");
                            //检测异常
                            Boolean lost = serviceConfigInfo.lostConnection();
                            if(lost){
                                //失联三次 删除该服务
                                logger.info(serviceConfigInfo.getServiceName()+"服务失联-删除服务");
                                ServiceConfig.removeService(serviceConfigInfo.getServiceCode());
                            }
                        }
                    }
                });

            }
        }
    }
}
